﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PServiceBus.Core.Interface;
using System.Collections.Concurrent;
using PServiceBus.Core.Runtime;
using PServiceBus.Core.Runtime.Extensions;
using PServiceBus.Core.Runtime.Topics;

namespace PServiceBus.Core.Manager {
    public class WorkerManager : IWorkerManager {

        private HashSet<IWorker> _workers;
        private object _lockObject = new object();

        private WorkerManager() {
            _workers = new HashSet<IWorker>(new FuncEqualityComparer<IWorker>((x, y) => x.TopicID == y.TopicID,
                h => h.TopicID.GetHashCode()));
           
        }

        private static IWorkerManager _current;
        public static IWorkerManager Current {
            get {
                if (_current == null) _current = new WorkerManager();
                return _current;
            }
        }
        #region IWorkerManager Members

        public void Attach(IWorker worker) {
            if (worker == null) return;
            lock (_lockObject) {
                if (!_workers.Contains(worker))
                    _workers.Add(worker);
                Add(worker);
            }
        }

        public void Detach(IWorker worker) {
            if (worker == null) return;
            lock (_lockObject) {
                _workers.Remove(worker);
                Delete(worker);
            }
        }

        private void Add(IWorker worker) {
            var topic = worker as ITopic;
            if (topic == null) return;
            TopicManager.Current.Attach(new TopicInfo(topic));
        }

        private void Add(IEnumerable<IWorker> workers) {
            TopicManager.Current.AttachMany(workers.Select(e => new TopicInfo(e as ITopic)));
        }

        private void Delete(IWorker worker) {
            var topic = worker as ITopic;
            if (topic == null) return;
            TopicManager.Current.Detach(new TopicInfo(topic));
        }

        private void Delete(IEnumerable<IWorker> workers) {
            TopicManager.Current.DetachMany(workers.Select(e => new TopicInfo(e as ITopic)));
        }

        public void Attach(IEnumerable<IWorker> workers) {
            lock (_lockObject) 
                foreach (var worker in workers) 
                    if (!_workers.Contains(worker))
                        _workers.Add(worker);
            Add(workers);
        }

        public void Detach(IEnumerable<IWorker> workers) {
            lock (_lockObject)
                foreach (var worker in workers) 
                    _workers.Remove(worker);
            Delete(workers);
        }

        public IEnumerable<IWorker> Workers {
            get { return _workers; }
        }

        #endregion
    }
}
